#define _CONTR_
#ifdef _CONTR_
#include <sstream>
#include <string>
#include <stdio.h>
#include <stdlib.h>
#include "ReadFifo.h"
#include "WriteFifo.h"
#include "Message.h"
#include "Logger.h"
#include "Semaforo.h"
#include "AirStripStack.h"
#include "ControllerStack.h"
#include "Config.h"
#include "Exception.h"

void assign_airstrip(unsigned long id, AirStripStack &free_air_strips,
		Semaforo * sem_free_airstrip, key_t sem_key)
{
	static const unsigned int response = 3;
	static const unsigned int sem_to_v = 4;

	std::stringstream name;
	name << "./tmp/Controler_flight";
	name << id;

	Logger::getInstance().logMessage(Logger::DEBUG, " Voy a abrir fifo escritura");
	WriteFifo fifo(name.str());
	fifo.open_();
	Logger::getInstance().logMessage(Logger::DEBUG, "Fifo abierto");

	Logger::getInstance().logMessage(Logger::DEBUG, " Tomar pista libre");
	Logger::getInstance().logMessage(Logger::TRACE, "reservando pista");
	unsigned long airstrip_n = free_air_strips.pop();
	Logger::getInstance().logMessage(Logger::DEBUG, "tomó pista libre: ");

	//Enviar mensaje con numero de pista
	Logger::getInstance().logMessage(Logger::TRACE, "asignando pista");
	Logger::getInstance().logMessage(Logger::DEBUG, " Envio mensaje con numero de pista");
	Message msg(response, airstrip_n);
	char *a_buffer = msg.serialize();
	int wr = fifo.write_(static_cast<void*> (a_buffer), msg.size());
	delete[] a_buffer;
	a_buffer = NULL;
	if (wr < msg.size()){
		Logger::getInstance().logMessage(Logger::ERROR, std::string("Error"));
	}

	Logger::getInstance().logMessage(Logger::DEBUG, " Envio mensaje con numero de semaforo");
	//Enviar mensaje con numero semaforo
	Message sem_msg(sem_to_v, sem_key);
	a_buffer = sem_msg.serialize();
	wr = fifo.write_(static_cast<void*> (a_buffer), sem_msg.size());
	delete[] a_buffer;
	a_buffer = NULL;
	if (wr < sem_msg.size()){
		Logger::getInstance().logMessage(Logger::ERROR, std::string("Error"));
	}
	fifo.close_();
	//esperar a que el avion deja de usar la pista
	Logger::getInstance().logMessage(Logger::DEBUG, " Espero que se libere la pista");
	sem_free_airstrip->p();
	//liberar la pista
	Logger::getInstance().logMessage(Logger::DEBUG, " Libero recurso");
	free_air_strips.push(airstrip_n);
	Logger::getInstance().logMessage(Logger::DEBUG, "Pista liberada: ");
}

void parse(char* arg, unsigned long& c){
	std::stringstream ss;
	ss << arg;
	ss >> c;
}

/* Main */
int main(int argc, char* argv[]) {

	static const ssize_t MSG_SIZE = sizeof(unsigned int) + sizeof(unsigned long);
	const std::string fifo_path_head = "./tmp/Tower_Contr_";
	//tomar parametros de entrada
	unsigned long controlerID = 0;
	char buffer[255];
	Logger::init();
	int controllers_q = Config::get_instance().get_int("controllers");
	int total_airstrips_number = Config::get_instance().get_int("airstrips");

	std::string fifo_name = fifo_path_head;
	Semaforo *sem_free_airstrip = NULL;

	// Parse the ID of the process
	parse(argv[1], controlerID);


	sprintf(buffer, "Controler N°%ld", controlerID);
	Logger::getInstance().setProcessInformation(buffer);


	//Inicializacion
	std::stringstream ss;
	ss << controlerID;
	fifo_name += ss.str();
	Logger::getInstance().logMessage(Logger::DEBUG, "Voy a abrir ReadFifo: " + fifo_name);
	ReadFifo fifo(fifo_name);
	Logger::getInstance().logMessage(Logger::TRACE, "Abro fifo de lectura");
	fifo.open_();

	Logger::getInstance().logMessage(Logger::DEBUG, " Inicializando semaforo y pilas");
	try {
		key_t sem_key = Semaforo::generarClave(fifo_name, controlerID);
		AirStripStack free_air_strips(AirStripStack::defaul_path, total_airstrips_number);
		ControllerStack free_controllers(ControllerStack::defaul_path, controllers_q);
		sem_free_airstrip = new Semaforo(sem_key);
		sem_free_airstrip->setVal(0);
		Logger::getInstance().logMessage(Logger::DEBUG, " Semaforo y pilas inicializados");


		//Agregar un graceful quit, meter el read de la condicion dentro del
		//cuepo del while
		//simulacion
		Logger::getInstance().logMessage(Logger::TRACE, "inicia simulación");
		int bytes_read = -1;
		do{
			bytes_read = fifo.read_(static_cast<void*> (buffer), MSG_SIZE);
			//rd da -1 en caso de error
			if ( bytes_read == -1 )
			{
				Logger::getInstance().logMessage(Logger::ERROR, std::string("Error al leer mensaje"));
				break;
			} else if (bytes_read == 0)
				//rd da 0 en caso de leer un EOF que significa que el
				//archivo solo está abierto en modo lectura por este proceso
			{
				Logger::getInstance().logMessage(Logger::DEBUG, "la torre cerro el canal");
			} else
			{
				unsigned long airflight_number = 0;
				Message msg(buffer, MSG_SIZE);
				Logger::getInstance().logMessage(Logger::TRACE, "mensaje leido");
				airflight_number = msg.getData();
				assign_airstrip(airflight_number, free_air_strips, sem_free_airstrip,
						sem_key);
				Logger::getInstance().logMessage(Logger::TRACE, "se encuentra libre.");
				free_controllers.push(controlerID);
				std::stringstream s;
				s << controlerID;
				Logger::getInstance().logMessage(Logger::TRACE, std::string("push de mi id: " + s.str()));
				s.clear();
			}
		} while(bytes_read > 0);
		Logger::getInstance().logMessage(Logger::DEBUG, "finaliza simulación");
		sem_free_airstrip->eliminar();
		delete sem_free_airstrip;
		sem_free_airstrip = NULL;
		Logger::getInstance().logMessage(Logger::DEBUG, "Cierro y borro recursos");
		fifo.close_();
	} catch (Exception & e){
		Logger::getInstance().logMessage(Logger::ERROR, e.get_error_description());
		sem_free_airstrip->eliminar();
		delete sem_free_airstrip;
		sem_free_airstrip = NULL;
	} catch (std::string & e){
		Logger::getInstance().logMessage(Logger::ERROR, e);
		sem_free_airstrip->eliminar();
		delete sem_free_airstrip;
		sem_free_airstrip = NULL;
	}
	return 0;
}
#endif
